from __future__ import annotations

import os
import signal
import threading
import time
from dataclasses import dataclass
from typing import Optional

import pydirectinput
import winsound
from pynput import keyboard, mouse

from app.base_worker import BaseWorker
from app.tray_icon import TrayIcon


# 常量配置
CLICK_INTERVAL_MS = 5  # 连击按下/抬起间隔（毫秒）
BEEP_FREQ_ON = 1000    # 开启提示音频率
BEEP_FREQ_OFF = 500    # 关闭提示音频率
BEEP_FREQ_EXIT = 400   # 退出提示音频率
BEEP_DURATION = 200    # 提示音时长（毫秒）


class ClickWorker(BaseWorker):
    """连击工作线程"""

    def __init__(self, condition: threading.Condition, running_checker, interval_ms: int) -> None:
        super().__init__("ClickWorker", condition, running_checker)
        self.interval = interval_ms / 1000.0
        # 配置PyDirectInput
        pydirectinput.FAILSAFE = False
        pydirectinput.PAUSE = 0

    def _run_work_loop(self) -> None:
        """执行连击工作循环"""
        try:
            pydirectinput.keyDown(']')
            time.sleep(0.001)
            pydirectinput.keyUp(']')
            time.sleep(self.interval - 0.001)
        except Exception as e:
            print(f"[ClickWorker] 连击操作异常: {e}")

    def cleanup(self) -> None:
        """清理连击相关资源"""
        try:
            pydirectinput.keyUp(']')
        except Exception as e:
            print(f"[ClickWorker] 清理按键状态异常: {e}")


class GameAssistController:
    """连击助手"""

    def __init__(self) -> None:
        
        # 状态变量
        self.click_enabled = False
        self.lbutton_pressed = False
        self._running = True
        self._click_running = False
        
        # 线程控制
        self._click_condition = threading.Condition()
        self._click_worker: Optional[ClickWorker] = None
        
        # UI组件
        self.tray_icon: Optional[TrayIcon] = None
        self._mouse_listener: Optional[mouse.Listener] = None
        self._keyboard_listener: Optional[keyboard.Listener] = None
        
        # 配置PyDirectInput
        pydirectinput.FAILSAFE = False
        pydirectinput.PAUSE = 0
        
        self._setup_signal_handlers()
        self._start_worker_threads()

    def _setup_signal_handlers(self) -> None:
        """设置信号处理器"""
        def signal_handler(signum, frame):
            self.stop_and_exit()

        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)
        if hasattr(signal, 'SIGBREAK'):
            signal.signal(signal.SIGBREAK, signal_handler)

    @staticmethod
    def _beep(freq: int, duration_ms: int = BEEP_DURATION) -> None:
        """播放提示音"""
        try:
            winsound.Beep(freq, duration_ms)
        except (OSError, RuntimeError):
            pass

    def start(self) -> None:
        """启动程序"""

        # 启动托盘图标
        try:
            self.tray_icon = TrayIcon(self)
            self.tray_icon.start()
        except (OSError, RuntimeError, ImportError) as e:
            print(f"[警告] 托盘图标启动失败: {e}")

        # 注册热键
        try:
            self._keyboard_listener = keyboard.GlobalHotKeys({
                '<f1>': self.toggle_click,
                '<ctrl>+<shift>+<f12>': self.stop_and_exit
            })
            self._keyboard_listener.start()
        except (OSError, RuntimeError, ImportError) as e:
            print(f"[警告] 热键注册失败: {e}")
            self._keyboard_listener = None

        # 注册鼠标监听器
        try:
            self._mouse_listener = mouse.Listener(
                on_click=self._on_mouse_click
            )
            self._mouse_listener.start()
        except (OSError, RuntimeError, ImportError) as e:
            print(f"[警告] 鼠标监听器注册失败: {e}")
            self._mouse_listener = None

        # 等待退出
        try:
            while self._running:
                time.sleep(0.1)
        except KeyboardInterrupt:
            pass
        finally:
            self.stop_and_exit()

    def _update_tray_status(self) -> None:
        """更新托盘图标状态"""
        if self.tray_icon:
            self.tray_icon.update_status()


    def toggle_click(self) -> None:
        """切换连击功能"""
        self.click_enabled = not self.click_enabled
        if self.click_enabled:
            self._beep(BEEP_FREQ_ON)
        else:
            self._beep(BEEP_FREQ_OFF)
            self._stop_click()

        self._update_tray_status()

    def stop_and_exit(self) -> None:
        """退出程序"""
        print("[GameAssist] 正在退出程序...")

        # 播放退出提示音
        self._beep(BEEP_FREQ_EXIT, 300)

        self._running = False

        # 停止工作线程
        if self._click_worker:
            self._click_worker.stop()

        # 停止托盘图标
        if self.tray_icon:
            self.tray_icon.stop()

        # 停止监听器
        if self._keyboard_listener:
            self._keyboard_listener.stop()
        if self._mouse_listener:
            self._mouse_listener.stop()

        print("[GameAssist] 程序已退出")
        os._exit(0)


    def _start_click(self) -> None:
        """启动连击"""
        self._click_running = True
        if self._click_worker:
            self._click_worker.notify()

    def _stop_click(self) -> None:
        """停止连击"""
        self._click_running = False
        if self._click_worker:
            self._click_worker.cleanup()

    def _on_mouse_click(self, x: int, y: int, button: mouse.Button, pressed: bool) -> None:
        """鼠标事件回调"""
        if not self._running:
            return

        if pressed and button == mouse.Button.left:
            self._on_left_down()
        elif not pressed and button == mouse.Button.left:
            self._on_left_up()

    def _on_left_down(self) -> None:
        """鼠标左键按下"""
        if not self._running:
            return

        self.lbutton_pressed = True

        # 启动连击功能
        if self.click_enabled:
            self._start_click()
        else:
            # 连击不启动时，"]"按键跟随鼠标左键
            pydirectinput.keyDown(']')

    def _on_left_up(self) -> None:
        """鼠标左键抬起"""
        if not self._running:
            return

        self.lbutton_pressed = False

        # 停止连击功能
        self._stop_click()
        
        # 连击不启动时，"]"按键跟随鼠标左键
        if not self.click_enabled:
            pydirectinput.keyUp(']')

    def _should_click(self) -> bool:
        """检查是否应该连击"""
        return self._click_running and self.lbutton_pressed and self.click_enabled

    def _start_worker_threads(self) -> None:
        """启动工作线程"""
        self._click_worker = ClickWorker(
            condition=self._click_condition,
            running_checker=self._should_click,
            interval_ms=CLICK_INTERVAL_MS
        )
        self._click_worker.start()
